iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0

自然語言很適合表達需求,卻不適合直接驅動企業系統。「幫忙找一間明天下午可以坐八人的會議室」對人類很自然,但系統仍要知道日期、時區、開始時間、持續多久、地點與是否需要立即預約。

若模型聽完句子就直接呼叫工具,任何漏欄、誤解或臆測都可能變成真實副作用。Typed Intent 的目的,是在自然語言與控制面之間建立一道可驗證的資料邊界。

Typed Intent 是候選,不是命令

Typed Intent 將使用者語句轉成固定欄位,例如:

{
  "action": "search",
  "resource_type": "meeting_space",
  "start_at": "2026-09-21T14:00:00+08:00",
  "duration_minutes": 60,
  "capacity": 8,
  "location": null,
  "needs_clarification": true
}

這份資料只表示模型對語句的解析結果。後端仍要進行 schema validation、語意驗證、權限檢查與必要的人工確認,通過後才能建立預約或修改真實資料。

把模型輸出視為不受信任的候選資料,可以避免「JSON 格式正確」被誤認為「業務操作正確」。

Schema 要描述控制面真正需要的資訊

Schema 不應照抄自然語言,而應對應後續流程的決策需求。常見欄位可分成幾類:

  • 動作:search、create、update、cancel。
  • 資源:resource type、resource ID、範圍或位置。
  • 時間:原始文字、標準化時間、時區與期間。
  • 數量:人數、金額、配額或優先級。
  • 限制:設備、無障礙需求、預算或政策條件。
  • 來源:原始輸入、語言、解析版本與 request ID。
  • 不確定性:缺少欄位、候選值、需不需要追問。

必要欄位要用 required 明確宣告;不允許模型自由新增的欄位可透過 additionalProperties: false 收斂。列舉值、數值範圍與字串格式也應盡可能寫入 schema。

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "additionalProperties": false,
  "properties": {
    "action": {
      "type": "string",
      "enum": ["search", "create", "update", "cancel"]
    },
    "capacity": {
      "type": "integer",
      "minimum": 1
    },
    "needs_clarification": {
      "type": "boolean"
    }
  },
  "required": ["action", "needs_clarification"]
}

Schema 能檢查結構與型別,但無法承擔所有業務規則。例如結束時間必須晚於開始時間、取消者必須是預約擁有者,仍需要一般程式碼或 policy engine 驗證。

缺少資訊就追問

最危險的做法,是為了完成 schema 而讓模型補出使用者沒有提供的值。像「明天下午」沒有單一開始時間,「附近」也需要參考位置。

缺少必要資訊時,解析結果應進入 NEEDS_CLARIFICATION,並提出最少而明確的問題:

請問希望幾點開始,以及預計使用多久?

不必一次詢問所有可選欄位。先收集會改變候選範圍或權限判斷的資訊,能縮短對話,也降低使用者負擔。

追問後要保留原始 intent 與新答案的關聯,避免重新解析時遺失已確認欄位。已確認的值也不應被後續模型輸出靜默覆寫。

模糊值要保留不確定性

有些語句不能立刻轉成單一值,但仍可保留候選:

{
  "time_expression": "明天下午",
  "candidate_start_times": [
    "2026-09-21T13:00:00+08:00",
    "2026-09-21T14:00:00+08:00"
  ],
  "selected_start_time": null,
  "needs_clarification": true
}

這種表示法比填入看似精確的時間安全。信心分數可以作為排序或監控訊號,但不應單獨決定高風險操作是否放行;模型輸出的 0.95 並不是經過校準的安全保證。

時間、身份與資源 ID 要由系統正規化

「明天」、「下週五」與「下午兩點」都依賴目前時間與時區。解析時至少要傳入明確的基準時間、使用者時區與 locale,輸出則同時保留原始文字和標準化值。

使用者提到「大會議室」時,模型可以辨識名稱,卻不應直接猜出資料庫 ID。正確流程是先查詢允許存取的資源清單,再由確定性程式完成名稱解析與權限過濾。

身份也不能從自然語言自行認定。像「幫主管取消預約」仍要從驗證過的 session、委派關係與 RBAC 取得 actor 身份,不能把句子中的角色當成授權證明。

Validation 應分層

一個安全的 Typed Intent pipeline 可以拆成:

  1. 結構驗證:JSON 是否符合 schema、型別與 required 欄位。
  2. 正規化:時間、單位、名稱與列舉值轉成標準格式。
  3. 語意驗證:欄位組合是否合理,例如期間不可為負數。
  4. 資源解析:將名稱映射到真實 ID,處理零筆或多筆候選。
  5. 政策驗證:確認 actor 是否有權執行,資源是否符合規則。
  6. 確認與提交:對有副作用的動作顯示摘要,確認後才 commit。

每一層都應回傳明確錯誤,而不是把所有失敗重新丟給模型自由解釋。像 INVALID_TIME_RANGERESOURCE_AMBIGUOUSPERMISSION_DENIED 能讓流程採取可預測的下一步。

用反例測試解析器

只測合法輸入,無法證明邊界可靠。測試集至少要涵蓋:

  • 缺少必要欄位。
  • 相對時間與跨時區輸入。
  • 同名資源與不存在的 ID。
  • 超出範圍的數量或期間。
  • 同一句話包含互相矛盾的限制。
  • 要求略過核准、冒用身份或修改無權存取的資源。
  • Prompt injection 試圖新增 schema 外欄位或任意 tool call。
  • 相同語意的不同說法、錯字與中英混用。

評估不只看整份 JSON 是否完全相同,也要分欄位計算正確率,並記錄 clarification precision、clarification recall、誤放行率與錯誤類型。對會產生副作用的流程,誤放行通常比多問一次更昂貴。

結論

Typed Intent 不是讓 LLM 直接控制工具,而是把模糊語言轉成可驗證的候選資料。Schema 負責限制結構,正規化與業務規則負責確認語意,RBAC 與 policy 負責授權,最後才由確定性程式提交副作用。

缺欄就追問,有歧義就保留候選,身份與資源 ID 交由受信任系統解析。建立這條邊界後,自然語言的彈性才不會滲入控制面。下一篇將延續這個基礎,定義 Agent 能呼叫哪些工具,以及每個 Tool Contract 應保證什麼。


參考資料


上一篇
Day 05|先定 State:企業流程不是一串 Prompt
下一篇
Day 07|Tool Contract:Agent 可以做事,但不能想做什麼就做什麼
系列文
從 BPM 到 Agentic Workflow:企業 AI 流程的狀態、控制與驗證10
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言